#include "electronicscalehorndiagram.h"
#include "electronicscaletool.h"
#include <QDebug>
#include <QDateTime>
#include "excelengine.h"

ElectronicScaleHornDiagram::ElectronicScaleHornDiagram()
{

}

ElectronicScaleHornDiagram::~ElectronicScaleHornDiagram()
{

}

bool ElectronicScaleHornDiagram::setSamples(const QList<electronicscale::Sample> &samples)
{
    m_samples = samples;

    // 提取数据
    if (!extract())
        return false;

    // 计算误差
    calculateErrors();
    return true;
}

void ElectronicScaleHornDiagram::calculateViewingWindowErrors(int viewingWindow)
{
    // 最多有多少个观测窗
    int m = (m_period - viewingWindow) / m_interval + 1;

    // 计算误差
    QList<double> errors;
    for (int i = 0; i < m; i++)
    {
        double error = 0;
        for (int j = i; j < i + viewingWindow; j++)
        {
            error += m_errors.at(j);
        }
        error = error * m_interval / viewingWindow;
        errors << error;
    }

    // 打包
    ViewingWindowError windowError;
    windowError.window = viewingWindow;
    windowError.errors = errors;

    // 记录该观测窗的误差数据
    foreach (auto e, m_viewingWindowErrors)
    {
        if (e.window == viewingWindow)
        {
            m_viewingWindowErrors.removeOne(e);
        }
    }
    m_viewingWindowErrors << windowError;
    std::sort(m_viewingWindowErrors.begin(), m_viewingWindowErrors.end());
}

void ElectronicScaleHornDiagram::calculateViewingWindowResult()
{
    m_viewingWindowResults.clear();
    ViewingWindowResult r;
    foreach (auto e, m_viewingWindowErrors)
    {
        r.window = e.window;
        std::sort(e.errors.begin(), e.errors.end());
        r.errorMax = e.errors.last();
        r.errorMin = e.errors.first();
        r.errorTotal = m_totalError;
        m_viewingWindowResults << r;
    }
}

QList<ElectronicScaleHornDiagram::ViewingWindowResult> ElectronicScaleHornDiagram::getViewingWindowResult() const
{
    return m_viewingWindowResults;
}

double ElectronicScaleHornDiagram::getTotalError() const
{
    return m_totalError;
}

void ElectronicScaleHornDiagram::setPeriod(int min)
{
    m_period = min;
}

int ElectronicScaleHornDiagram::getPeriod() const
{
    return m_period;
}

void ElectronicScaleHornDiagram::setInterval(int min)
{
    m_interval = min;
}

int ElectronicScaleHornDiagram::getInterval() const
{
    return m_interval;
}

void ElectronicScaleHornDiagram::setDensity(double value)
{
    m_density = value;
}

double ElectronicScaleHornDiagram::getDensity() const
{
    return m_density;
}

void ElectronicScaleHornDiagram::setTargetRate(double rate)
{
    m_targetRate = rate;
}

double ElectronicScaleHornDiagram::getTargetRate() const
{
    return m_targetRate;
}

bool ElectronicScaleHornDiagram::exportHornDiagramToXlsx(const QString &path, const QList<ViewingWindowResult> &results, const QString &sheetName)
{
    if (path.isEmpty())
        return false;

    bool ret = false;

    ExcelEngine excel;
    ret = excel.OpenSheet(path, sheetName, QIODevice::Truncate);
    if (!ret)
        return false;

    // 设置表头
    QVariant var;
    var.setValue(QString("Viewing Window(minutes)"));
    excel.SetCellData(1, 1, var);
    var.setValue(QString("Ep(max)"));
    excel.SetCellData(1, 2, var);
    var.setValue(QString("Ep(min)"));
    excel.SetCellData(1, 3, var);
    var.setValue(QString("Total Average Error"));
    excel.SetCellData(1, 4, var);

    int row = 2;
    foreach (auto r, results)
    {
        QVariant var;
        var.setValue(r.window);
        excel.SetCellData(row, 1, var);
        var.clear();
        var.setValue(r.errorMax);
        excel.SetCellData(row, 2, var);
        var.clear();
        var.setValue(r.errorMin);
        excel.SetCellData(row, 3, var);
        var.clear();
        var.setValue(r.errorTotal);
        excel.SetCellData(row, 4, var);
        row++;
    }
    excel.Save();
    excel.Close();

    return true;
}

bool ElectronicScaleHornDiagram::extract()
{
    // 原始数据太少
    if (m_samples.size() <= 1)
        return false;

    // 原始数据的采样周期比要求的采样周期短
    if ((m_samples.last().time - m_samples.first().time) < m_period * 60 * 1000)
        return false;

    m_standardSamples.clear();

    electronicscale::Sample prevSample = m_samples.at(0);
    m_standardSamples << m_samples.at(0); // 以第一个点为起始点
    qint64 nextTime = prevSample.time + m_interval * 60 * 1000; // 下一个标准点时间
    int number = m_period / m_interval + 1; // period内共有多少个数据
    for (int i = 1; i < m_samples.size(); i++)
    {
        const electronicscale::Sample &s = m_samples.at(i);
        if (s.time >= nextTime)
        {
            // 找到对齐的点
            electronicscale::Sample sample =
                    ElectronicScaleTool::getLinearWeight(nextTime, prevSample, s);
            m_standardSamples << sample;

            nextTime += m_interval * 60 * 1000; // 下一个标准点时间

            // 只取period内的数据
            if (m_standardSamples.size() >= number)
                break;
        }
        else
        {
            prevSample = s;
        }

        // 只处理前面一小时数据
        if (s.time >= m_samples.at(0).time + m_period * 60 * 1000)
            break;
    }
    return true;
}

void ElectronicScaleHornDiagram::calculateErrors()
{
    m_errors.clear();

    for (int i = 1; i < m_standardSamples.size(); i++)
    {
        // 流速
        double delta = m_standardSamples.at(i).weight.value - m_standardSamples.at(i - 1).weight.value;
        double time = (double)(m_standardSamples.at(i).time - m_standardSamples.at(i - 1).time) / 1000.0;
        double rate = delta / time * 3600.0 / m_density;

        // 误差百分比
        double error = (rate - m_targetRate) / m_targetRate * 100;

        m_errors << error;
    }

    // 总的平均百分比流量误差
    double delta = m_standardSamples.last().weight.value - m_standardSamples.first().weight.value;
    double time = (double)(m_standardSamples.last().time - m_standardSamples.first().time) / 1000.0;
    double rate = delta / time * 3600.0 / m_density;
    m_totalError = (rate - m_targetRate) / m_targetRate * 100;
}

